// -*-mode:c++; coding:utf-8-*-

#ifndef _XBASE_TABLE_MUTATOR_HPP_
#define _XBASE_TABLE_MUTATOR_HPP_

#include "protocol_packet.hpp"
#include "sync_handler.hpp"
#include "async_write.hpp"
#include "async_module_stats.hpp"

#include "session_manager.hpp"

namespace xbase
{

	struct table_lister {};

	class table_deletion
	{
	public:
		explicit
		table_deletion(const std::string &table_name)
			: m_table_name(table_name) {}

		const std::string &table_name() const {
			return m_table_name;
		}

	private:
		const std::string &m_table_name;
	};

	class table_creation
	{
	public:
		typedef boost::system::error_code error_code;
		
		typedef protocol::group_options group_options;
		typedef protocol::family_options family_options;

	public:
		explicit
		table_creation(const std::string &table_name)
			: m_table_info(table_name) {}
		
		error_code add_group(const std::string &group_name,
				     const group_options &options) {
			error_code ec;
			if(m_table_info.get_group_info(group_name) != NULL)
			{
				ec = error::group_already_exists;
			}
			else if(! options.valid())
			{
				ec = error::bad_option;
			}
			else
			{
				m_table_info.m_groups.push_back(
					protocol::group_info(group_name, options)
					);
			}
			return ec;
		}
		
		error_code add_family(const std::string &family_name,
				      const std::string &group_name,
				      const family_options &options) {
			error_code ec;
			if(m_table_info.get_family_info(family_name) != NULL)
			{
				ec = error::family_already_exists;
			}
			else if(m_table_info.get_group_info(group_name) == NULL)
			{
				ec = error::group_not_exists;
			}
			else if(! options.valid())
			{
				ec = error::bad_option;
			}
			else
			{
				m_table_info.m_families.push_back(
					protocol::family_info(family_name,
							      group_name,
							      options)
					);
			}
			return ec;
		}

		const protocol::table_info &table_info() const {
			return m_table_info;
		}

	private:
		protocol::table_info m_table_info;
	};

	class table_mutator
		: public async_module_base<io_service_pool::user_level,
					   io_service_pool::xbase_level>
	{
	public:
		typedef async_module_base<io_service_pool::user_level,
					  io_service_pool::xbase_level> base_type;
		typedef table_mutator this_type;
		typedef boost::intrusive_ptr<this_type> ptr_type;

		typedef protocol::packet_type< protocol::create_table_request::type >::type create_table_req;
		typedef protocol::packet_type< protocol::create_table_request::type >::ptr_type create_table_req_ptr;

		typedef protocol::packet_type< protocol::create_table_response::type >::type create_table_resp;
		typedef protocol::packet_type< protocol::create_table_response::type >::ptr_type create_table_resp_ptr;

		typedef protocol::packet_type< protocol::delete_table_request::type >::type delete_table_req;
		typedef protocol::packet_type< protocol::delete_table_request::type >::ptr_type delete_table_req_ptr;

		typedef protocol::packet_type< protocol::delete_table_response::type >::type delete_table_resp;
		typedef protocol::packet_type< protocol::delete_table_response::type >::ptr_type delete_table_resp_ptr;

		typedef protocol::packet_type< protocol::list_table_request::type >::type list_table_req;
		typedef protocol::packet_type< protocol::list_table_request::type >::ptr_type list_table_req_ptr;

		typedef protocol::packet_type< protocol::list_table_response::type >::type list_table_resp;
		typedef protocol::packet_type< protocol::list_table_response::type >::ptr_type list_table_resp_ptr;

		typedef boost::system::error_code error_code;
		typedef session_manager::endpoint_type endpoint_type;
		
		typedef boost::function<void(const error_code&)> create_handler_type;
		typedef basic_sync_handler<> sync_create_handler_type;

		typedef create_handler_type delete_handler_type;
		typedef sync_create_handler_type sync_delete_handler_type;

		typedef std::vector<std::string> table_name_vector;
		typedef boost::function<void(table_name_vector, const error_code &)> list_handler_type;
		typedef basic_sync_handler<table_name_vector> sync_list_handler_type;

	public:
		table_mutator(io_service_pool &pool,
			      session_manager &manager,
			      const endpoint_type &master_address)
			: base_type(pool, "table_mutator")
			, m_session_manager(manager)
			, m_master_address(master_address) {}

		template<typename Handler>
		inline
		void async_apply(const table_creation &creation,
				 Handler handler) {
			async_create_table(creation.table_info(),
					   handler);
		}

		template<typename Handler>
		inline
		void async_apply(const table_deletion &deletion,
				 Handler handler) {
			async_delete_table(deletion.table_name(),
					   handler);
		}

		template<typename Handler>
		inline
		void async_apply(const table_lister &lister,
				 Handler handler) {
			async_list_table(handler);
		}

		template<typename Handler>
		inline
		void async_create_table(const protocol::table_info &info,
					Handler handler) {
			m_create_req_ptr.reset(new create_table_req);
			m_create_req_ptr->body().m_table_info = info;
			m_create_handler = handler;

			if(! info.valid())
			{
				on_create_error(error::bad_table_info);
			}
			else
			{
				on_async_create_table();
			}
		}

		template<typename Handler>
		inline
		void async_delete_table(const std::string &table_name,
					Handler handler) {
			m_delete_req_ptr.reset(new delete_table_req);
			m_delete_req_ptr->body().m_table_name = table_name;
			m_delete_handler = handler;

			on_async_delete_table();
		}

		template<typename Handler>
		inline
		void async_list_table(Handler handler) {
			if(! m_list_req_ptr)
			{
				m_list_req_ptr.reset(new list_table_req);
				m_list_req_ptr->body().m_start_table_name = std::string();
				m_list_req_ptr->body().m_table_number = 0;
			}
			m_list_handler = handler;
			on_async_list_table();
		}

	protected:
		void on_async_delete_table() {
			async_write(m_session_manager,
				    m_master_address,
				    m_delete_req_ptr,
				    boost::bind(&this_type::on_delete_response,
						this_ptr(),
						_1, _2));
		}

		void on_delete_response(protocol::packet_ptr packet,
					const error_code &session_ec);

		void on_delete_error(const error_code &ec);

		void dispatch_delete(const error_code &ec) {
			m_delete_req_ptr.reset();
			delete_handler_type tmp = m_delete_handler;
			m_delete_handler = delete_handler_type();
			this->get_upper_level_service().dispatch(
				boost::bind(tmp, ec)
				);
		}

		void on_async_create_table() {
			async_write(m_session_manager,
				    m_master_address,
				    m_create_req_ptr,
				    boost::bind(&this_type::on_create_response,
						this_ptr(),
						_1, _2));
		}

		void on_create_response(protocol::packet_ptr packet,
					const error_code &session_ec);

		void on_create_error(const error_code &ec);

		void dispatch_create(const error_code &ec) {
			m_create_req_ptr.reset();
			create_handler_type tmp = m_create_handler;
			m_create_handler = create_handler_type();
			this->get_upper_level_service().dispatch(
				boost::bind(tmp, ec)
				);
		}

		void on_async_list_table() {
			async_write(m_session_manager,
				    m_master_address,
				    m_list_req_ptr,
				    boost::bind(&this_type::on_list_response,
						this_ptr(),
						_1, _2));
		}

		void on_list_response(protocol::packet_ptr packet,
				      const error_code &session_ec);

		void on_list_error(const table_name_vector &vec,
				   const error_code &ec);

		void dispatch_list(const table_name_vector &vec,
				   const error_code &ec) {
			// 保留 list 请求
			list_handler_type tmp = m_list_handler;
			m_list_handler = list_handler_type();
			this->get_upper_level_service().dispatch(
				boost::bind(tmp, vec, ec)
				);
		}

		ptr_type this_ptr() {
			return ptr_type(this);
		}

	private:
		session_manager &m_session_manager;
		const endpoint_type &m_master_address;

		create_table_req_ptr m_create_req_ptr;
		create_handler_type m_create_handler;
		
		delete_table_req_ptr m_delete_req_ptr;
		delete_handler_type m_delete_handler;

		list_table_req_ptr m_list_req_ptr;
		list_handler_type m_list_handler;
	};

	typedef table_mutator::ptr_type table_mutator_ptr;

	template<typename Handler>
	inline
	void async_apply(io_service_pool &pool,
			 session_manager &manager,
			 const table_mutator::endpoint_type &master_address,
			 const table_creation &creation,
			 Handler handler) {
		table_mutator_ptr ptr(new_async_module(table_mutator,
						       pool, manager, master_address));
		ptr->async_apply(creation, handler);
	}

	template<typename Handler>
	inline
	void async_apply(io_service_pool &pool,
			 session_manager &manager,
			 const table_mutator::endpoint_type &master_address,
			 const table_deletion &deletion,
			 Handler handler) {
		table_mutator_ptr ptr(new_async_module(table_mutator,
						       pool, manager, master_address));
		ptr->async_apply(deletion, handler);
	}

} // namespace xbase

#endif	// _XBASE_TABLE_MUTATOR_HPP_
